Patch from Dov Grobgeld to implement auto-bidi-direction for GtkTextView
authorOwen Taylor <otaylor@redhat.com>
Mon, 1 Mar 2004 16:07:45 +0000 (16:07 +0000)
committerOwen Taylor <otaylor@src.gnome.org>
Mon, 1 Mar 2004 16:07:45 +0000 (16:07 +0000)
Mon Mar  1 10:41:27 2004  Owen Taylor  <otaylor@redhat.com>

        Patch from Dov Grobgeld to implement auto-bidi-direction
        for GtkTextView (#118543)

        * gtk/gtktextbtree.[ch]: Resolve bidi base direction
        for each line by propagating backwards/forwards as
        necessary.

        * gtk/gtktextlayout.[ch] gtk/gtktextview.c: Set the
        bidi base direction for the ;ine with the cursor from
        the keyboard direction. Add gtk_text_layout_set_keyboard_direction().

Mon Mar  1 10:31:11 2004  Owen Taylor  <otaylor@redhat.com>

        * gtk/gtkentry.[ch]: Implement auto-bidi-direction,
        based on a patch from Dov Grobgeld. (#118540)

ChangeLog
ChangeLog.pre-2-10
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
gtk/gtkentry.h
gtk/gtktextbtree.c
gtk/gtktextbtree.h
gtk/gtktextlayout.c
gtk/gtktextlayout.h
gtk/gtktextview.c

index 7372e4ea3c15762d1b85807b2c7e3dd4af429400..b167cde2004773c36af899e97368ead5101e391d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,19 @@
+Mon Mar  1 10:41:27 2004  Owen Taylor  <otaylor@redhat.com>
+
+       Patch from Dov Grobgeld to implement auto-bidi-direction
+       for GtkTextView (#118543)
+
+       * gtk/gtktextbtree.[ch]: Resolve bidi base direction
+       for each line by propagating backwards/forwards as
+       necessary.
+
+       * gtk/gtktextlayout.[ch] gtk/gtktextview.c: Set the 
+       bidi base direction for the ;ine with the cursor from 
+       the keyboard direction. Add gtk_text_layout_set_keyboard_direction().
+       
 Mon Mar  1 10:31:11 2004  Owen Taylor  <otaylor@redhat.com>
 
-       * gtk/gtkentry.c: Implement auto-bidi-direction,
+       * gtk/gtkentry.[ch]: Implement auto-bidi-direction,
        based on a patch from Dov Grobgeld. (#118540)
 
 Sun Feb 29 22:01:49 2004  Owen Taylor  <otaylor@redhat.com>
index 7372e4ea3c15762d1b85807b2c7e3dd4af429400..b167cde2004773c36af899e97368ead5101e391d 100644 (file)
@@ -1,6 +1,19 @@
+Mon Mar  1 10:41:27 2004  Owen Taylor  <otaylor@redhat.com>
+
+       Patch from Dov Grobgeld to implement auto-bidi-direction
+       for GtkTextView (#118543)
+
+       * gtk/gtktextbtree.[ch]: Resolve bidi base direction
+       for each line by propagating backwards/forwards as
+       necessary.
+
+       * gtk/gtktextlayout.[ch] gtk/gtktextview.c: Set the 
+       bidi base direction for the ;ine with the cursor from 
+       the keyboard direction. Add gtk_text_layout_set_keyboard_direction().
+       
 Mon Mar  1 10:31:11 2004  Owen Taylor  <otaylor@redhat.com>
 
-       * gtk/gtkentry.c: Implement auto-bidi-direction,
+       * gtk/gtkentry.[ch]: Implement auto-bidi-direction,
        based on a patch from Dov Grobgeld. (#118540)
 
 Sun Feb 29 22:01:49 2004  Owen Taylor  <otaylor@redhat.com>
index 7372e4ea3c15762d1b85807b2c7e3dd4af429400..b167cde2004773c36af899e97368ead5101e391d 100644 (file)
@@ -1,6 +1,19 @@
+Mon Mar  1 10:41:27 2004  Owen Taylor  <otaylor@redhat.com>
+
+       Patch from Dov Grobgeld to implement auto-bidi-direction
+       for GtkTextView (#118543)
+
+       * gtk/gtktextbtree.[ch]: Resolve bidi base direction
+       for each line by propagating backwards/forwards as
+       necessary.
+
+       * gtk/gtktextlayout.[ch] gtk/gtktextview.c: Set the 
+       bidi base direction for the ;ine with the cursor from 
+       the keyboard direction. Add gtk_text_layout_set_keyboard_direction().
+       
 Mon Mar  1 10:31:11 2004  Owen Taylor  <otaylor@redhat.com>
 
-       * gtk/gtkentry.c: Implement auto-bidi-direction,
+       * gtk/gtkentry.[ch]: Implement auto-bidi-direction,
        based on a patch from Dov Grobgeld. (#118540)
 
 Sun Feb 29 22:01:49 2004  Owen Taylor  <otaylor@redhat.com>
index 7372e4ea3c15762d1b85807b2c7e3dd4af429400..b167cde2004773c36af899e97368ead5101e391d 100644 (file)
@@ -1,6 +1,19 @@
+Mon Mar  1 10:41:27 2004  Owen Taylor  <otaylor@redhat.com>
+
+       Patch from Dov Grobgeld to implement auto-bidi-direction
+       for GtkTextView (#118543)
+
+       * gtk/gtktextbtree.[ch]: Resolve bidi base direction
+       for each line by propagating backwards/forwards as
+       necessary.
+
+       * gtk/gtktextlayout.[ch] gtk/gtktextview.c: Set the 
+       bidi base direction for the ;ine with the cursor from 
+       the keyboard direction. Add gtk_text_layout_set_keyboard_direction().
+       
 Mon Mar  1 10:31:11 2004  Owen Taylor  <otaylor@redhat.com>
 
-       * gtk/gtkentry.c: Implement auto-bidi-direction,
+       * gtk/gtkentry.[ch]: Implement auto-bidi-direction,
        based on a patch from Dov Grobgeld. (#118540)
 
 Sun Feb 29 22:01:49 2004  Owen Taylor  <otaylor@redhat.com>
index 7372e4ea3c15762d1b85807b2c7e3dd4af429400..b167cde2004773c36af899e97368ead5101e391d 100644 (file)
@@ -1,6 +1,19 @@
+Mon Mar  1 10:41:27 2004  Owen Taylor  <otaylor@redhat.com>
+
+       Patch from Dov Grobgeld to implement auto-bidi-direction
+       for GtkTextView (#118543)
+
+       * gtk/gtktextbtree.[ch]: Resolve bidi base direction
+       for each line by propagating backwards/forwards as
+       necessary.
+
+       * gtk/gtktextlayout.[ch] gtk/gtktextview.c: Set the 
+       bidi base direction for the ;ine with the cursor from 
+       the keyboard direction. Add gtk_text_layout_set_keyboard_direction().
+       
 Mon Mar  1 10:31:11 2004  Owen Taylor  <otaylor@redhat.com>
 
-       * gtk/gtkentry.c: Implement auto-bidi-direction,
+       * gtk/gtkentry.[ch]: Implement auto-bidi-direction,
        based on a patch from Dov Grobgeld. (#118540)
 
 Sun Feb 29 22:01:49 2004  Owen Taylor  <otaylor@redhat.com>
index 3c06f472dc751bd92a1c9694de5a7e1fe64281f4..be8b4a64460606c5f942cfdb3864f3d79ce2976d 100644 (file)
@@ -93,6 +93,7 @@ struct _GtkEntry
   
   guint        select_words : 1;
   guint        select_lines : 1;
+  guint        resolved_dir : 4; /* PangoDirection */
   guint   button;
   guint   blink_timeout;
   guint   recompute_idle;
index 6d340a74aedca8bc9fabd81771aeb0f354c799ed..c62d55855d600a81942e6952f95d0f52bbe48861 100644 (file)
@@ -554,6 +554,174 @@ _gtk_text_btree_segments_changed (GtkTextBTree *tree)
  * Indexable segment mutation
  */
 
+/*
+ *  The following function is responsible for resolving the bidi direction
+ *  for the lines between start and end. But it also calculates any
+ *  dependent bidi direction for surrounding lines that change as a result
+ *  of the bidi direction decisions within the range. The function is
+ *  trying to do as little propagation as is needed.
+ */
+static void
+gtk_text_btree_resolve_bidi (GtkTextIter *start,
+                            GtkTextIter *end)
+{
+  GtkTextBTree *tree = _gtk_text_iter_get_btree (start);
+  GtkTextLine *start_line, *end_line, *start_line_prev, *end_line_next, *line;
+  PangoDirection last_strong, dir_above_propagated, dir_below_propagated;
+
+  /* Resolve the strong bidi direction for all lines between
+   * start and end.
+  */
+  start_line = _gtk_text_iter_get_text_line (start);
+  start_line_prev = _gtk_text_line_previous (start_line);
+  end_line = _gtk_text_iter_get_text_line (end);
+  end_line_next = _gtk_text_line_next (end_line);
+  
+  line = start_line;
+  while (line && line != end_line_next)
+    {
+      /* Loop through the segments and search for a strong character
+       */
+      GtkTextLineSegment *seg = line->segments;
+      line->dir_strong = PANGO_DIRECTION_NEUTRAL;
+      
+      while (seg)
+        {
+          if (seg->byte_count > 0)
+            {
+             PangoDirection pango_dir;
+
+              pango_dir = pango_find_base_dir (seg->body.chars,
+                                              seg->byte_count);
+             
+              if (pango_dir != PANGO_DIRECTION_NEUTRAL)
+                {
+                  line->dir_strong = pango_dir;
+                  break;
+                }
+            }
+          seg = seg->next;
+        }
+
+      line = _gtk_text_line_next (line);
+    }
+
+  /* Sweep forward */
+
+  /* The variable dir_above_propagated contains the forward propagated
+   * direction before start. It is neutral if start is in the beginning
+   * of the buffer.
+   */
+  dir_above_propagated = PANGO_DIRECTION_NEUTRAL;
+  if (start_line_prev)
+    dir_above_propagated = start_line_prev->dir_propagated_forward;
+
+  /* Loop forward and propagate the direction of each paragraph 
+   * to all neutral lines.
+   */
+  line = start_line;
+  last_strong = dir_above_propagated;
+  while (line != end_line_next)
+    {
+      if (line->dir_strong != PANGO_DIRECTION_NEUTRAL)
+        last_strong = line->dir_strong;
+      
+      line->dir_propagated_forward = last_strong;
+      
+      line = _gtk_text_line_next (line);
+    }
+
+  /* Continue propagating as long as the previous resolved forward
+   * is different from last_strong.
+   */
+  {
+    GtkTextIter end_propagate;
+    
+    while (line &&
+          line->dir_strong == PANGO_DIRECTION_NEUTRAL &&
+          line->dir_propagated_forward != last_strong)
+      {
+        GtkTextLine *prev = line;
+        line->dir_propagated_forward = last_strong;
+        
+        line = _gtk_text_line_next(line);
+        if (!line)
+          {
+            line = prev;
+            break;
+          }
+      }
+
+    /* The last line to invalidate is the last line before the
+     * line with the strong character. Or in case of the end of the
+     * buffer, the last line of the buffer. (There seems to be an
+     * extra "virtual" last line in the buffer that must not be used
+     * calling _gtk_text_btree_get_iter_at_line (causes crash). Thus the
+     * _gtk_text_line_previous is ok in that case as well.)
+     */
+    line = _gtk_text_line_previous (line);
+    _gtk_text_btree_get_iter_at_line (tree, &end_propagate, line, 0);
+    _gtk_text_btree_invalidate_region (tree, end, &end_propagate);
+  }
+  
+  /* Sweep backward */
+
+  /* The variable dir_below_propagated contains the backward propagated
+   * direction after end. It is neutral if end is at the end of
+   * the buffer.
+  */
+  dir_below_propagated = PANGO_DIRECTION_NEUTRAL;
+  if (end_line_next)
+    dir_below_propagated = end_line_next->dir_propagated_back;
+
+  /* Loop backward and propagate the direction of each paragraph 
+   * to all neutral lines.
+   */
+  line = end_line;
+  last_strong = dir_below_propagated;
+  while (line != start_line_prev)
+    {
+      if (line->dir_strong != PANGO_DIRECTION_NEUTRAL)
+        last_strong = line->dir_strong;
+
+      line->dir_propagated_back = last_strong;
+
+      line = _gtk_text_line_previous (line);
+    }
+
+  /* Continue propagating as long as the resolved backward dir
+   * is different from last_strong.
+   */
+  {
+    GtkTextIter start_propagate;
+
+    while (line &&
+          line->dir_strong == PANGO_DIRECTION_NEUTRAL &&
+          line->dir_propagated_back != last_strong)
+      {
+        GtkTextLine *prev = line;
+        line->dir_propagated_back = last_strong;
+
+        line = _gtk_text_line_previous (line);
+        if (!line)
+          {
+            line = prev;
+            break;
+          }
+      }
+
+    /* We only need to invalidate for backwards propagation if the
+     * line we ended up on didn't get a direction from forwards
+     * propagation.
+     */
+    if (line && line->dir_propagated_forward == PANGO_DIRECTION_NEUTRAL)
+      {
+        _gtk_text_btree_get_iter_at_line (tree, &start_propagate, line, 0);
+        _gtk_text_btree_invalidate_region(tree, &start_propagate, start);
+      }
+  }
+}
+
 void
 _gtk_text_btree_delete (GtkTextIter *start,
                         GtkTextIter *end)
@@ -884,6 +1052,8 @@ _gtk_text_btree_delete (GtkTextIter *start,
   /* Re-initialize our iterators */
   _gtk_text_btree_get_iter_at_line (tree, start, start_line, start_byte_offset);
   *end = *start;
+  
+  _gtk_text_btree_resolve_bidi (start, end);
 }
 
 void
@@ -1050,6 +1220,8 @@ _gtk_text_btree_insert (GtkTextIter *iter,
 
     /* Convenience for the user */
     *iter = end;
+    
+    _gtk_text_btree_resolve_bidi (&start, &end);
   }
 }
 
@@ -4498,6 +4670,9 @@ gtk_text_line_new (void)
   GtkTextLine *line;
 
   line = g_new0(GtkTextLine, 1);
+  line->dir_strong = PANGO_DIRECTION_NEUTRAL;
+  line->dir_propagated_forward = PANGO_DIRECTION_NEUTRAL;
+  line->dir_propagated_back = PANGO_DIRECTION_NEUTRAL;
 
   return line;
 }
index 28fe390f0c811e9479d2de2caaad49735eebc3c7..59ef11408ace536a11dbd12e8addc5b28f5babb4 100644 (file)
@@ -216,6 +216,9 @@ struct _GtkTextLine {
   GtkTextLineSegment *segments; /* First in ordered list of segments
                                  * that make up the line. */
   GtkTextLineData *views;      /* data stored here by views */
+  guchar dir_strong;                /* BiDi algo dir of line */
+  guchar dir_propagated_back;       /* BiDi algo dir of next line */
+  guchar dir_propagated_forward;    /* BiDi algo dir of prev line */
 };
 
 
index 157435a8b8036abb6fdb877ff11d7323a612793e..9c98dd789933777cf8805cc224442ca6af866b18 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
+#define GTK_TEXT_LAYOUT_GET_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_TEXT_LAYOUT, GtkTextLayoutPrivate))
+
+typedef struct _GtkTextLayoutPrivate GtkTextLayoutPrivate;
+
+struct _GtkTextLayoutPrivate
+{
+  /* Cache the line that the cursor is positioned on, as the keyboard
+     direction only influences the direction of the cursor line.
+  */
+  GtkTextLine *cursor_line;
+};
+
 static GtkTextLineData *gtk_text_layout_real_wrap (GtkTextLayout *layout,
                                                    GtkTextLine *line,
                                                    /* may be NULL */
@@ -110,6 +122,22 @@ static void gtk_text_layout_invalidate_all (GtkTextLayout *layout);
 
 static PangoAttribute *gtk_text_attr_appearance_new (const GtkTextAppearance *appearance);
 
+static void gtk_text_layout_mark_set_handler    (GtkTextBuffer     *buffer,
+                                                const GtkTextIter *location,
+                                                GtkTextMark       *mark,
+                                                gpointer           data);
+static void gtk_text_layout_buffer_insert_text  (GtkTextBuffer     *textbuffer,
+                                                GtkTextIter       *iter,
+                                                gchar             *str,
+                                                gint               len,
+                                                gpointer           data);
+static void gtk_text_layout_buffer_delete_range (GtkTextBuffer     *textbuffer,
+                                                GtkTextIter       *start,
+                                                GtkTextIter       *end,
+                                                gpointer           data);
+
+static void gtk_text_layout_update_cursor_line (GtkTextLayout *layout);
+
 enum {
   INVALIDATED,
   CHANGED,
@@ -209,6 +237,8 @@ gtk_text_layout_class_init (GtkTextLayoutClass *klass)
                   GTK_TYPE_OBJECT,
                   G_TYPE_INT,
                   G_TYPE_INT);
+  
+  g_type_class_add_private (object_class, sizeof (GtkTextLayoutPrivate));
 }
 
 static void
@@ -284,6 +314,16 @@ gtk_text_layout_set_buffer (GtkTextLayout *layout,
       _gtk_text_btree_remove_view (_gtk_text_buffer_get_btree (layout->buffer),
                                   layout);
 
+      g_signal_handlers_disconnect_by_func (layout->buffer, 
+                                            G_CALLBACK (gtk_text_layout_mark_set_handler), 
+                                            layout);
+      g_signal_handlers_disconnect_by_func (layout->buffer, 
+                                            G_CALLBACK (gtk_text_layout_buffer_insert_text), 
+                                            layout);
+      g_signal_handlers_disconnect_by_func (layout->buffer, 
+                                            G_CALLBACK (gtk_text_layout_buffer_delete_range), 
+                                            layout);
+
       g_object_unref (layout->buffer);
       layout->buffer = NULL;
     }
@@ -295,6 +335,14 @@ gtk_text_layout_set_buffer (GtkTextLayout *layout,
       g_object_ref (buffer);
 
       _gtk_text_btree_add_view (_gtk_text_buffer_get_btree (buffer), layout);
+
+      /* Bind to all signals that move the insert mark. */
+      g_signal_connect_after (layout->buffer, "mark_set",
+                              G_CALLBACK (gtk_text_layout_mark_set_handler), layout);
+      g_signal_connect_after (layout->buffer, "insert_text",
+                              G_CALLBACK (gtk_text_layout_buffer_insert_text), layout);
+      g_signal_connect_after (layout->buffer, "delete_range",
+                              G_CALLBACK (gtk_text_layout_buffer_delete_range), layout);
     }
 }
 
@@ -374,6 +422,25 @@ gtk_text_layout_set_cursor_direction (GtkTextLayout   *layout,
     }
 }
 
+/**
+ * gtk_text_layout_set_keyboard_direction:
+ * @keyboard_dir: the current direction of the keyboard.
+ *
+ * Sets the keyboard direction; this is used as for the bidirectional
+ * base direction for the line with the cursor if the line contains
+ * only neutral characters.
+ **/
+void
+gtk_text_layout_set_keyboard_direction (GtkTextLayout   *layout,
+                                       GtkTextDirection keyboard_dir)
+{
+  if (keyboard_dir != layout->keyboard_direction)
+    {
+      layout->keyboard_direction = keyboard_dir;
+      gtk_text_layout_invalidate_cursor_line (layout);
+    }
+}
+
 /**
  * gtk_text_layout_get_buffer:
  * @layout: a #GtkTextLayout
@@ -704,23 +771,33 @@ gtk_text_layout_invalidate_cache (GtkTextLayout *layout,
 static void
 gtk_text_layout_invalidate_cursor_line (GtkTextLayout *layout)
 {
-  GtkTextIter iter;
-  GtkTextLine *line;
+  GtkTextLayoutPrivate *priv = GTK_TEXT_LAYOUT_GET_PRIVATE (layout);
   GtkTextLineData *line_data;
 
-  gtk_text_buffer_get_iter_at_mark (layout->buffer, &iter,
-                                   gtk_text_buffer_get_mark (layout->buffer, "insert"));
+  if (priv->cursor_line == NULL)
+    return;
   
-  line = _gtk_text_iter_get_text_line (&iter);
-  line_data = _gtk_text_line_get_data (line, layout);
+  line_data = _gtk_text_line_get_data (priv->cursor_line, layout);
   if (line_data)
     {
-      gtk_text_layout_invalidate_cache (layout, line);
-      _gtk_text_line_invalidate_wrap (line, line_data);
+      gtk_text_layout_invalidate_cache (layout, priv->cursor_line);
+      _gtk_text_line_invalidate_wrap (priv->cursor_line, line_data);
       gtk_text_layout_invalidated (layout);
     }
 }
 
+static void
+gtk_text_layout_update_cursor_line(GtkTextLayout *layout)
+{
+  GtkTextLayoutPrivate *priv = GTK_TEXT_LAYOUT_GET_PRIVATE (layout);
+  GtkTextIter iter;
+
+  gtk_text_buffer_get_iter_at_mark (layout->buffer, &iter,
+                                    gtk_text_buffer_get_mark (layout->buffer, "insert"));
+  
+  priv->cursor_line = _gtk_text_iter_get_text_line (&iter);
+}
+
 static void
 gtk_text_layout_real_invalidate (GtkTextLayout *layout,
                                  const GtkTextIter *start,
@@ -1121,26 +1198,46 @@ totally_invisible_line (GtkTextLayout *layout,
 
 static void
 set_para_values (GtkTextLayout      *layout,
-                 GtkTextAttributes *style,
+                 PangoDirection      base_dir,
+                 GtkTextAttributes  *style,
                  GtkTextLineDisplay *display)
 {
   PangoAlignment pango_align = PANGO_ALIGN_LEFT;
   int layout_width;
 
-  display->direction = style->direction;
+  switch (base_dir)
+    {
+    /* If no base direction was found, then use the style direction */
+    case PANGO_DIRECTION_NEUTRAL :
+      display->direction = style->direction;
 
-  if (display->direction == GTK_TEXT_DIR_LTR)
-    display->layout = pango_layout_new (layout->ltr_context);
-  else
+      /* Override the base direction */
+      if (display->direction == GTK_TEXT_DIR_RTL)
+        base_dir = PANGO_DIRECTION_RTL;
+      else
+        base_dir = PANGO_DIRECTION_LTR;
+      
+      break;
+    case PANGO_DIRECTION_RTL :
+      display->direction = GTK_TEXT_DIR_RTL;
+      break;
+    default:
+      display->direction = GTK_TEXT_DIR_LTR;
+      break;
+    }
+  
+  if (display->direction == GTK_TEXT_DIR_RTL)
     display->layout = pango_layout_new (layout->rtl_context);
+  else
+    display->layout = pango_layout_new (layout->ltr_context);
 
   switch (style->justification)
     {
     case GTK_JUSTIFY_LEFT:
-      pango_align = (style->direction == GTK_TEXT_DIR_LTR) ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
+      pango_align = (base_dir == PANGO_DIRECTION_LTR) ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT;
       break;
     case GTK_JUSTIFY_RIGHT:
-      pango_align = (style->direction == GTK_TEXT_DIR_LTR) ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
+      pango_align = (base_dir == PANGO_DIRECTION_LTR) ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
       break;
     case GTK_JUSTIFY_CENTER:
       pango_align = PANGO_ALIGN_CENTER;
@@ -1683,6 +1780,7 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
                                   GtkTextLine   *line,
                                   gboolean       size_only)
 {
+  GtkTextLayoutPrivate *priv = GTK_TEXT_LAYOUT_GET_PRIVATE (layout);
   GtkTextLineDisplay *display;
   GtkTextLineSegment *seg;
   GtkTextIter iter;
@@ -1696,6 +1794,7 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
   GSList *cursor_segs = NULL;
   GSList *tmp_list1, *tmp_list2;
   gboolean saw_widget = FALSE;
+  PangoDirection base_dir;
   
   g_return_val_if_fail (line != NULL, NULL);
 
@@ -1728,6 +1827,18 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
   if (totally_invisible_line (layout, line, &iter))
     return display;
 
+  /* Find the bidi base direction */
+  base_dir = line->dir_propagated_forward;
+  if (base_dir == PANGO_DIRECTION_NEUTRAL)
+    base_dir = line->dir_propagated_back;
+
+  if (line == priv->cursor_line &&
+      line->dir_strong == PANGO_DIRECTION_NEUTRAL)
+    {
+      base_dir = (layout->keyboard_direction == GTK_TEXT_DIR_LTR) ?
+        PANGO_DIRECTION_LTR : PANGO_DIRECTION_RTL;
+    }
+  
   /* Allocate space for flat text for buffer
    */
   text_allocated = _gtk_text_line_byte_count (line);
@@ -1758,7 +1869,7 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
            */
           if (!para_values_set)
             {
-              set_para_values (layout, style, display);
+              set_para_values (layout, base_dir, style, display);
               para_values_set = TRUE;
             }
 
@@ -1927,7 +2038,7 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
   if (!para_values_set)
     {
       style = get_style (layout, &iter);
-      set_para_values (layout, style, display);
+      set_para_values (layout, base_dir, style, display);
       release_style (layout, style);
     }
   
@@ -3070,3 +3181,40 @@ gtk_text_layout_spew (GtkTextLayout *layout)
           layout->height, layout->screen_width);
 #endif
 }
+
+/* Catch all situations that move the insertion point.
+ */
+static void
+gtk_text_layout_mark_set_handler (GtkTextBuffer     *buffer,
+                                  const GtkTextIter *location,
+                                  GtkTextMark       *mark,
+                                  gpointer           data)
+{
+  GtkTextLayout *layout = GTK_TEXT_LAYOUT (data);
+
+  if (mark == gtk_text_buffer_get_insert (buffer))
+    gtk_text_layout_update_cursor_line (layout);
+}
+
+static void
+gtk_text_layout_buffer_insert_text (GtkTextBuffer *textbuffer,
+                                   GtkTextIter   *iter,
+                                   gchar         *str,
+                                   gint           len,
+                                   gpointer       data)
+{
+  GtkTextLayout *layout = GTK_TEXT_LAYOUT (data);
+
+  gtk_text_layout_update_cursor_line (layout);
+}
+
+static void
+gtk_text_layout_buffer_delete_range (GtkTextBuffer *textbuffer,
+                                    GtkTextIter   *start,
+                                    GtkTextIter   *end,
+                                    gpointer       data)
+{
+  GtkTextLayout *layout = GTK_TEXT_LAYOUT (data);
+
+  gtk_text_layout_update_cursor_line (layout);
+}
index 58e8e97c4580fdbad4fc68ffc0ae361400b3a8d7..fa6802ebb07b6fe1910ab43b4e6b5769b1ee402c 100644 (file)
@@ -165,6 +165,11 @@ struct _GtkTextLayout
    */
   guint cursor_direction : 2;
 
+  /* The keyboard direction is used to default the alignment when
+     there are no strong characters.
+  */
+  guint keyboard_direction : 2;
+
   /* The preedit string and attributes, if any */
 
   gchar *preedit_string;
@@ -265,7 +270,9 @@ void               gtk_text_layout_set_contexts          (GtkTextLayout     *lay
                                                          PangoContext      *ltr_context,
                                                          PangoContext      *rtl_context);
 void               gtk_text_layout_set_cursor_direction  (GtkTextLayout     *layout,
-                                                         GtkTextDirection   direction);
+                                                          GtkTextDirection   direction);
+void               gtk_text_layout_set_keyboard_direction (GtkTextLayout     *layout,
+                                                          GtkTextDirection keyboard_dir);
 void               gtk_text_layout_default_style_changed (GtkTextLayout     *layout);
 
 void gtk_text_layout_set_screen_width       (GtkTextLayout     *layout,
index 5238aa71f5bbc0c0a6552d509cf5e07ca755527a..dbb4e2ffcba89b7e6ba22cb5985a1bdd7de2fde0 100644 (file)
@@ -5620,26 +5620,28 @@ gtk_text_view_check_keymap_direction (GtkTextView *text_view)
 {
   if (text_view->layout)
     {
-      gboolean split_cursor;
-      GtkTextDirection new_dir;
       GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view));
-  
+      GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (text_view)));
+      GtkTextDirection new_cursor_dir;
+      GtkTextDirection new_keyboard_dir;
+      gboolean split_cursor;
+
       g_object_get (settings,
                    "gtk-split-cursor", &split_cursor,
                    NULL);
+      
+      if (gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_LTR)
+       new_keyboard_dir = GTK_TEXT_DIR_LTR;
+      else
+       new_keyboard_dir  = GTK_TEXT_DIR_RTL;
+  
       if (split_cursor)
-       {
-         new_dir = GTK_TEXT_DIR_NONE;
-       }
+       new_cursor_dir = GTK_TEXT_DIR_NONE;
       else
-       {
-         GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (text_view)));
-         new_dir = (gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_LTR) ?
-           GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
-       }
+       new_cursor_dir = new_keyboard_dir;
       
-      if (text_view->layout->cursor_direction != new_dir)
-       gtk_text_layout_set_cursor_direction (text_view->layout, new_dir);
+      gtk_text_layout_set_cursor_direction (text_view->layout, new_cursor_dir);
+      gtk_text_layout_set_keyboard_direction (text_view->layout, new_keyboard_dir);
     }
 }